<?php
namespace Think\Upload\Driver;
namespace Common\Org\Upload\Driver;

use \Aliyun\OSS\OSSClient;

/**
 *
 * @authors Your Name (you@example.org)
 * @date    2014-07-11 13:42:25
 * @version $Id$
 */

require_once dirname(__FILE__) . '/Aliyun/aliyun.php';

class aliyun {

	private $config = array(
		'AccessKeyId' => '', //OSS用户
		'AccessKeySecret' => '', //OSS密码
		'domain' => '', //OSS空间路径
		'Bucket' => '', //空间名称
		'Endpoint' => '', //超时时间
	);

	/**
	 * 本地上传错误信息
	 * @var string
	 */
	private $error = '';

	/**
	 * 构造函数，用于设置上传根路径
	 * @param array $config 配置
	 */
	public function __construct($config) {
		/* 默认配置 */
		$this->config = array_merge($this->config, $config);
	}

	/**
	 * 检测上传根目录(OSS上传时支持自动创建目录，直接返回)
	 * @param string $rootpath 根目录
	 * @return boolean true-检测通过，false-检测失败
	 */
	public function checkRootPath($rootpath) {
		/* 设置根目录 */
		$this->rootPath = trim($rootpath, './') . '/';
		return true;
	}

	/**
	 * 检测上传目录(OSS上传时支持自动创建目录，直接返回)
	 * @param  string $savepath 上传目录
	 * @return boolean          检测结果，true-通过，false-失败
	 */
	public function checkSavePath($savepath) {
		return true;
	}

	/**
	 * 创建文件夹 (OSS上传时支持自动创建目录，直接返回)
	 * @param  string $savepath 目录名称
	 * @return boolean          true-创建成功，false-创建失败
	 */
	public function mkdir($savepath) {
		return true;
	}

	/**
	 * 保存指定文件
	 * @param  array $file 保存的文件信息
	 * @param  boolean $replace 同名文件是否覆盖
	 * @return boolean          保存状态，true-成功，false-失败
	 */
	public function save(&$file, $replace = true) {
		$size = $file['size'];
		$sliceSize = 1 * 1024 * 1024; //大于1M分片大小
		if ($size > $sliceSize) {
			return $this->save_by_part($file, $replace);
		} else {
			return $this->save_by_all($file, $replace);
		}
	}

	/******一次性上传**/
	public function save_by_all(&$file, $replace = true) {
		$key = $file['savepath'] . $file['savename'];
		$content = fopen($file['tmp_name'], 'r');
		$size = $file['size'];
		$client = $this->client();
		$save = $client->putObject(array(
			'Bucket' => $this->config['Bucket'],
			'Key' => $key,
			'Content' => $content,
			'ContentLength' => $size,
			'addHeader' => $file['addHeader'],
		));
		if ($save) {
			return OSS . $key;
		} else {
			return false;
		}
	}

	/****分片上传***/
	public function save_by_part(&$file, $replace = true) {
		$progress_key = md5(json_encode(array('fileName' => $file['name'], 'session_id' => session_id())));
		S($progress_key, 0);
		$key = $file['savepath'] . $file['savename'];
		$content = fopen($file['tmp_name'], 'r');
		$size = $file['size'];
		$client = $this->client();
		$r = $client->InitiateMultipartUpload(array(
			'Bucket' => $this->config['Bucket'],
			'Key' => $key,
			'Content' => $content,
			'ContentLength' => $size,
			'addHeader' => $file['addHeader'],
		));
		$UploadId = $r->getUploadId();
		/****分片*/
		$offset = 0;
		$flag = 0;
		$sliceSize = 1 * 1024 * 1024; //分片大小
		$ParNumber = 1;
		$fileSize = $size;
		$fileContent = $file['tmp_name'];
		$PartETags = array();
		while ($flag != 1) {
			$dataSize = 0;
			//计算本次上传分片的大小
			if ($offset + $sliceSize > $fileSize) {
				$dataSize = $fileSize - $offset;
			} else {
				$dataSize = $sliceSize;
			}
			$part = file_get_contents($fileContent, false, NULL, $offset, $dataSize);
			$res = $client->uploadPart(array(
				'Bucket' => $this->config['Bucket'],
				'Key' => $key,
				'UploadId' => $UploadId,
				'Content' => $part,
				'PartSize' => $dataSize,
				'PartNumber' => $ParNumber,
			));
			$ETag = $res->getETag();
			$PartETags[] = array(
				'PartNumber' => $ParNumber,
				'ETag' => $ETag,
			);
			if (!empty($ETag) && $flag == 0) {
				$offset += $dataSize;
				$ParNumber++;
			}
			$progress = $offset / $fileSize; //上传进度
			S($progress_key, $progress); //上传进度结束
			if ($offset == $fileSize) {
				$flag = 1;
				S($progress_key, 1, 10); //上传进度结束
				$r = $client->completeMultipartUpload(array(
					'Bucket' => $this->config['Bucket'],
					'Key' => $key,
					'UploadId' => $UploadId,
					'PartETags' => $PartETags,
				));
				if ($r->getKey()) {
					return OSS . $key;
				} else {
					return false;
				}
			}

		}
	}

	/**
	 * 获取最后一次上传错误信息
	 * @return string 错误信息
	 */
	public function getError() {
		return $this->client->errorStr;
	}

	//创建client对象
	function client() {
		$client = OSSClient::factory(array(
			'Endpoint' => $this->config['Endpoint'],
			'AccessKeyId' => $this->config['AccessKeyId'],
			'AccessKeySecret' => $this->config['AccessKeySecret'],
		));
		return $client;
	}
}